package com.ist.acceleratedrawdemo

import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BlurMaskFilter
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PathEffect
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.graphics.RectF
import android.os.Handler
import android.os.Message
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import com.ist.accelerate.DpApi
import com.ist.accelerate.EventStruct
import com.ist.acceleratedrawdemo.SpManager.Companion.instance

/**
 * Created by Quqixing on 2020/7/24
 */
class AccelerateView @JvmOverloads constructor(
    private val mContext: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(
    mContext, attrs, defStyleAttr
) {
    var mode = MODE_DRAW_PATH
    private var mOldMode = MODE_DRAW_PATH
    var isAccelerate = false
    lateinit var mDefaultPaint: Paint
    lateinit var mEraserPaint: Paint
    lateinit var mPath: Path
    lateinit var mCurrTmpPath: Path
    var mCanvas: Canvas? = null
    var mCurrLines: MutableList<Line?> = ArrayList()
    var mAllLines: MutableList<Line> = ArrayList()
    var mBitmap: Bitmap? = null
    var accelerateBitmap: Bitmap? = null
    var bgBitmap: Bitmap? = null
    lateinit var mPathMatrix: Matrix
    var factor4k2k = 2

    fun setBgColor(bgColor: Int) {
        bgBitmap!!.eraseColor(bgColor) //设置白色背景
        invalidate()
    }

    private fun init() {
        mBitmap = Bitmap.createBitmap(1920 * factor4k2k, 1080 * factor4k2k, Bitmap.Config.ARGB_8888)
        accelerateBitmap =
            Bitmap.createBitmap(1920 * factor4k2k, 1080 * factor4k2k, Bitmap.Config.ARGB_8888)
        bgBitmap =
            Bitmap.createBitmap(1920 * factor4k2k, 1080 * factor4k2k, Bitmap.Config.ARGB_8888)
        bgBitmap!!.eraseColor( /*Color.parseColor("#F03D2B")*/Color.WHITE) //设置白色背景
        mDefaultPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mDefaultPaint.color = Color.parseColor("#F03D2B")
        mDefaultPaint.strokeWidth = 0.1f
        mDefaultPaint.style = Paint.Style.STROKE
        mDefaultPaint.pathEffect = PathEffect()
        mDefaultPaint.strokeCap = Paint.Cap.ROUND
        mDefaultPaint.strokeJoin = Paint.Join.ROUND
        mDefaultPaint.maskFilter = BlurMaskFilter(0.001f, BlurMaskFilter.Blur.NORMAL)
        mEraserPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mEraserPaint.color = Color.BLUE
        mEraserPaint.style = Paint.Style.STROKE
        mEraserPaint.strokeWidth = 3f
        mPath = Path()
        mCurrTmpPath = Path()
        mPathMatrix = Matrix()
        mPathMatrix.postTranslate(0.5f, 0.5f)
        mPathMatrix.postScale(0.5f, 0.5f)
        if ("off" != DpApi.dpIsEnable()) {
            isAccelerate = true
        }
        Log.d(TAG, "init: dpIsEnable=" + DpApi.dpIsEnable())
    }

    fun clearAll() {
        mAllLines.clear()
        if (false) { //若是使用加速画bitmap，需要用这样的方法来达到清除的效果，不然后面的加速画bitmap会有过程残留
            val rect = Rect(0, 0, 3840, 2160)
            val c = Canvas(mBitmap!!)
            c.drawBitmap(bgBitmap!!, rect, rect, null)
        } else {
            mBitmap!!.eraseColor(Color.TRANSPARENT)
        }
        invalidate()
    }

    fun reDrawAll() {
        mBitmap!!.eraseColor(Color.TRANSPARENT)
        val canvas = Canvas(mBitmap!!)
        for (i in mAllLines.indices) {
            val line = mAllLines[i]
            canvas.drawPath(line.path, line.paint)
        }
        invalidate()
    }

    fun setAllLines(lines: MutableList<Line>) {
        mAllLines = lines
    }

    fun obtainAllLines(): List<Line> {
        val lines: MutableList<Line> = ArrayList()
        for (i in mAllLines.indices) {
            val line = Line()
            line.paint = mAllLines[i].paint
            line.path = mAllLines[i].path
            line.actionPointId = mAllLines[i].actionPointId
            line.preX = mAllLines[i].preX
            line.preY = mAllLines[i].preY
            line.preControlX = mAllLines[i].preControlX
            line.preControlY = mAllLines[i].preControlY
            lines.add(line)
        }
        return lines
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return handleTouchEvent(event, false)
    }

    /**
     * 判断输入加速的event是否有效，因为输入加速的事件EventStruct是一直获取到的，不管view有没有焦点，这里需要配合
     * Android原生的onTouchEvent事件来判定，是否真的事件有效（触摸到这个view，且down的时候返回true）。
     * EventStruct的Down事件在MotionEvent的Down事件之后。
     */
    private var bLinuxEventValid = false
    fun onTouchStruct(event: EventStruct): Boolean {
        val ee = event.toMotionEvent()
        val result = handleTouchEvent(ee, true)
        ee.recycle()
        return result
    }

    private fun handleTouchEvent(event: MotionEvent, inputAccelerate: Boolean): Boolean {
        //---------------判断是否用输入加速事件的参考判断方法-------------------//
        if (inputAccelerate) {
            Log.d(
                TAG, "handleTouchEvent: action=" + event.action + ", x=" + event.x + ", y="
                        + event.y + ", id=" + event.getPointerId(0)
            )
            if (!bLinuxEventValid) { //这个输入加速只应用在书写上
                return false
            }
        } else { //Android原生事件流程，辅助判断输入加速的事件是否有效
            if (DpApi.bLinuxInput) { //通过加速的接口，获取到系统是否具备输入加速的能力
                if (event.actionMasked == MotionEvent.ACTION_DOWN) {
                    bLinuxEventValid = true //说明点击到了这个view
                    //start: 如果还有其他场景不使用应用加速，可以参考这个把bLinuxEventValid设置为false
                    if (event.touchMajor >= 50) { //触发到板擦，不用输入加速，走Android原生的事件流程
                        mOldMode = mode
                        mode = MODE_TOUCH_ERASE
                    }
                    if (mode != MODE_DRAW_PATH) {
                        bLinuxEventValid = false
                    }
                    //end: 如果还有其他场景不使用应用加速，可以参考这个把bLinuxEventValid设置为false；
                    Log.i(TAG, "dpa use inputAccelerate, ACTION_DOWN===")
                }
                if (bLinuxEventValid) {
                    return true
                }
            }
            bLinuxEventValid = false
        }
        //----------------判断是否用输入加速事件的参考判断方法-------------------//
        val action = event.actionMasked
        when (action) {
            MotionEvent.ACTION_DOWN -> {
                mHandler.removeMessages(MSG_DP_CANCEL)
                mCurrLines.clear()
                if (event.touchMajor >= 50) {
                    mOldMode = mode
                    mode = MODE_TOUCH_ERASE
                }
                if (isEraseMode) {
                    //mHandler.sendEmptyMessage(MSG_DP_CANCEL);
                } else if (isDrawPath && isAccelerate) {
                }
                run {
                    val pointId = event.getPointerId(event.actionIndex)
                    Log.d(TAG, "按下的时候, pointerId=$pointId")
                    val x = event.getX(event.actionIndex)
                    val y = event.getY(event.actionIndex)
                    val line = if (this.isDrawShape) Shape() else Line()
                    line.actionPointId = pointId
                    line.paint = generateLinePaint(event)
                    line.paintABGR = toABGR(line.paint)
                    line.preX = x
                    line.preY = y
                    line.preControlX = x
                    line.preControlY = y
                    line.path.moveTo(x, y)
                    //加速下只多指画线
                    if (!this.isAccelerate || this.isDrawPath || event.action == MotionEvent.ACTION_DOWN) {
                        mCurrLines.add(line)
                        mAllLines.add(line)
                    }
                    if (!this.isAccelerate) {
                        if (this.isDrawShape) {
                            (line as Shape).onDown(event)
                        }
                        invalidate()
                    } else {
                        if (this.isEraseMode) {
                        } else if (this.isDrawShape) {
                            (line as Shape).onDown(event)
                        }
                    }
                }
            }

            MotionEvent.ACTION_POINTER_DOWN -> {
                val pointId = event.getPointerId(event.actionIndex)
                Log.d(TAG, "按下的时候, pointerId=$pointId")
                val x = event.getX(event.actionIndex)
                val y = event.getY(event.actionIndex)
                val line = if (isDrawShape) Shape() else Line()
                line.actionPointId = pointId
                line.paint = generateLinePaint(event)
                line.paintABGR = toABGR(line.paint)
                line.preX = x
                line.preY = y
                line.preControlX = x
                line.preControlY = y
                line.path.moveTo(x, y)
                if (!isAccelerate || isDrawPath || event.action == MotionEvent.ACTION_DOWN) {
                    mCurrLines.add(line)
                    mAllLines.add(line)
                }
                if (!isAccelerate) {
                    if (isDrawShape) {
                        (line as Shape).onDown(event)
                    }
                    invalidate()
                } else {
                    if (isEraseMode) {
                    } else if (isDrawShape) {
                        (line as Shape).onDown(event)
                    }
                }
            }

            MotionEvent.ACTION_MOVE -> {
                val t = System.currentTimeMillis()
                var i = 0
                while (i < event.pointerCount) {
                    val pointerId = event.getPointerId(i)
                    val x = event.getX(i)
                    val y = event.getY(i)
                    var j = 0
                    while (j < mCurrLines.size) {
                        val line = mCurrLines[j]
                        if (pointerId == line!!.actionPointId) {
                            val endX = (x + line.preX) / 2
                            val endY = (y + line.preY) / 2
                            Log.d(
                                TAG,
                                "handleTouchEvent: action=" + event.action + ", x=" + event.x + ", y="
                                        + event.y + ", id=" + event.getPointerId(0)
                            )
                            mCurrTmpPath.reset()
                            mCurrTmpPath.moveTo(line.preControlX, line.preControlY)
                            mCurrTmpPath.cubicTo(
                                line.preControlX, line.preControlY,
                                line.preX, line.preY, endX, endY
                            )
                            line.path.addPath(mCurrTmpPath)
                            line.preControlX = (x + line.preX) / 2
                            line.preControlY = (y + line.preY) / 2
                            line.preX = x
                            line.preY = y
                            if (isAccelerate) {
                                //Log.i(TAG, "onTouchEvent: mode = "+ mCurrMode);
                                if (isEraseMode) {
                                    //Log.i(TAG, "onTouchEvent: 橡皮 ");
                                    val c = Canvas(mBitmap!!)
                                    c.drawPath(mCurrTmpPath, line.paint)
                                    val canvas = Canvas(accelerateBitmap!!)
                                    val rect = Rect()
                                    val rectF = RectF()
                                    mCurrTmpPath.computeBounds(rectF, true)
                                    val s = line.paint.strokeWidth / 2 + 10
                                    rect[(rectF.left - s).toInt(), (rectF.top - s).toInt(), (rectF.right + s).toInt()] =
                                        (rectF.bottom + s).toInt()
                                    canvas.drawBitmap(bgBitmap!!, rect, rect, null)
                                    canvas.drawBitmap(mBitmap!!, rect, rect, null)
                                    canvas.drawCircle(
                                        line.preX, line.preY,
                                        line.paint.strokeWidth / 2, mEraserPaint!!
                                    )
                                    //Log.i(TAG, "onTouchEvent: rect="+rect.toShortString());
                                    if (DpApi.getType() == DpApi.AccelerateType.GEN2_9666_2K) {
                                        val dst = RectF(rect)
                                        DpApi.dpDrawBitmap(
                                            accelerateBitmap,
                                            rect,
                                            dst,
                                            mDefaultPaint
                                        )
                                    } else {
                                        DpApi.dpDrawBitmap(
                                            accelerateBitmap,
                                            rect,
                                            rect,
                                            mDefaultPaint
                                        )
                                    }
                                } else if (isDrawShape) {
                                    //Log.i(TAG, "onTouchEvent: 图形 ");
                                    val lastR = (line as Shape?)!!.vagueRectF
                                    (line as Shape?)!!.onMove(event)
                                    val currR = (line as Shape?)!!.vagueRectF
                                    val allR = RectF(currR)
                                    allR.union(lastR)
                                    val canvas = Canvas(accelerateBitmap!!)
                                    val rect = Rect()
                                    allR.round(rect)
                                    rect[rect.left - 10, rect.top - 10, rect.right + 10] =
                                        rect.bottom + 10
                                    canvas.drawBitmap(bgBitmap!!, rect, rect, null)
                                    canvas.drawBitmap(mBitmap!!, rect, rect, null)
                                    canvas.drawRect((line as Shape?)!!.rectF, line.paint)
                                    if (DpApi.getType() == DpApi.AccelerateType.GEN2_9666_2K) {
                                        val dst = RectF(rect)
                                        DpApi.dpDrawBitmap(
                                            accelerateBitmap,
                                            rect,
                                            dst,
                                            mDefaultPaint
                                        )
                                    } else {
                                        DpApi.dpDrawBitmap(
                                            accelerateBitmap,
                                            rect,
                                            rect,
                                            mDefaultPaint
                                        )
                                    }
                                } else {
                                    //Log.i(TAG, "onTouchEvent: 笔迹 ");
                                    //mCurrTmpPath.transform(mPathMatrix);
                                    DpApi.dpDrawPath(mCurrTmpPath, line.paintABGR)
                                    Log.d(TAG, "handleTouchEvent: move accelerate")
                                }
                            } else {
                                val canvas = Canvas(mBitmap!!)
                                if (isDrawShape) {
                                    (line as Shape?)!!.onMove(event)
                                } else if (isEraseMode) {
                                    val rectF = RectF()
                                    mCurrTmpPath.computeBounds(rectF, true)
                                    val rect = Rect()
                                    rectF.roundOut(rect)
                                    val padding = line.paint.strokeWidth.toInt()
                                    rect[rect.left - padding, rect.top - padding, rect.right + padding] =
                                        rect.bottom + padding
                                    canvas.save()
                                    canvas.clipRect(rect)
                                    canvas.drawPath(line.path, line.paint)
                                    canvas.restore()
                                    //invalidate(rect);
                                }
                            }
                        }
                        j++
                    }
                    i++
                }
                if (!isAccelerate) {
                    invalidate()
                }
            }

            MotionEvent.ACTION_UP -> {
                Log.d(TAG, "抬起的时候, 太太太=")
                run {
                    Log.d(TAG, "抬起的时候, pointerId=")
                    val index = event.actionIndex
                    val pointerId = event.getPointerId(index)
                    val canvas = Canvas(mBitmap!!)
                    var line: Line? = null
                    var finded = false
                    var i = 0
                    while (i < event.pointerCount && !finded) {
                        var j = 0
                        while (j < mCurrLines.size && !finded) {
                            line = mCurrLines[j]
                            if (line!!.actionPointId == pointerId) {
                                // 最后抬手的时候，需要重新把内容画到画布上，
                                // 使用Android原生机制刷新一次
                                if (this.isDrawPath) {
                                    canvas.drawPath(line!!.path, line!!.paint)
                                } else if (this.isDrawShape) {
                                    canvas.drawRect((line as Shape?)!!.rectF, line!!.paint)
                                }
                                finded = true
                            }
                            j++
                        }
                        i++
                    }
                    mCurrLines.remove(line)
                    if (!this.isAccelerate) {
                        invalidate()
                    } else {
                        //取消锁定画面
                        if (action == MotionEvent.ACTION_UP) {
                            mHandler.removeMessages(MSG_DP_CANCEL)
                            mHandler.sendEmptyMessageDelayed(MSG_DP_CANCEL, 500)
                            invalidate()
                            mContext.sendBroadcast(Intent(CHANGE_VIEW_ALPHA))
                        }
                    }
                    if (this.mode == MODE_TOUCH_ERASE && action == MotionEvent.ACTION_UP) {
                        this.mode = mOldMode
                    }
                }
            }

            MotionEvent.ACTION_POINTER_UP -> {
                Log.d(TAG, "抬起的时候, pointerId=")
                val index = event.actionIndex
                val pointerId = event.getPointerId(index)
                val canvas = Canvas(mBitmap!!)
                var line: Line? = null
                var finded = false
                var i = 0
                while (i < event.pointerCount && !finded) {
                    var j = 0
                    while (j < mCurrLines.size && !finded) {
                        line = mCurrLines[j]
                        if (line!!.actionPointId == pointerId) {
                            if (isDrawPath) {
                                canvas.drawPath(line!!.path, line!!.paint)
                            } else if (isDrawShape) {
                                canvas.drawRect((line as Shape?)!!.rectF, line!!.paint)
                            }
                            finded = true
                        }
                        j++
                    }
                    i++
                }
                mCurrLines.remove(line)
                if (!isAccelerate) {
                    invalidate()
                } else {
                    if (action == MotionEvent.ACTION_UP) {
                        mHandler.removeMessages(MSG_DP_CANCEL)
                        mHandler.sendEmptyMessageDelayed(MSG_DP_CANCEL, 500)
                        invalidate()
                        mContext.sendBroadcast(Intent(CHANGE_VIEW_ALPHA))
                    }
                }
                if (mode == MODE_TOUCH_ERASE && action == MotionEvent.ACTION_UP) {
                    mode = mOldMode
                }
            }
        }
        return true
    }

    val isEraseMode: Boolean
        get() = mode == MODE_TOUCH_ERASE || mode == MODE_ERASE
    val isDrawShape: Boolean
        get() = mode == MODE_DRAW_SHAPE
    val isDrawPath: Boolean
        get() = mode == MODE_DRAW_PATH

    private fun generateLinePaint(event: MotionEvent): Paint {
        val paint = Paint(mDefaultPaint)
        if (mode == MODE_TOUCH_ERASE) {
            paint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.CLEAR))
            paint.strokeWidth = event.touchMajor * 1.5f
        } else if (mode == MODE_ERASE) {
            paint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.CLEAR))
            paint.strokeWidth = instance!!.getFloat(SpManager.KEY_ERASER_WIDTH, 10f)
        } else {
            paint.strokeWidth = instance!!.getFloat(SpManager.KEY_STROKE_WIDTH, 1f)
            paint.setColor(instance!!.getInt(SpManager.KEY_STROKE_COLOR, -0x1))
            val filter = BlurMaskFilter(0.1f, BlurMaskFilter.Blur.NORMAL)
            paint.setMaskFilter(filter)
            /*if (SpManager.getInstance().getBoolean(SpManager.KEY_BLUR_ENABLE, true)) {
                float blurRadius = SpManager.getInstance().getFloat(SpManager.KEY_BLUR_SIZE, 1);*/
            /*paint.getStrokeWidth() > 1 ? 0.2f : 0.1f*/ /*;
                BlurMaskFilter.Blur type = BlurMaskFilter.Blur.NORMAL;
                switch (SpManager.getInstance().getInt(SpManager.KEY_BLUR_TYPE, 0)) {
                    case 0:
                        type = BlurMaskFilter.Blur.NORMAL;
                        break;
                    case 1:
                        type = BlurMaskFilter.Blur.SOLID;
                        break;
                    case 2:
                        type = BlurMaskFilter.Blur.OUTER;
                        break;
                    case 3:
                        type = BlurMaskFilter.Blur.INNER;
                        break;
                }
                //Log.d(TAG, "generateLinePaint: type="+SpManager.getInstance().getInt(SpManager.KEY_BLUR_TYPE, 0));
                BlurMaskFilter filter = new BlurMaskFilter(blurRadius, type);
                paint.setMaskFilter(filter);
            }*/
        }
        return paint
    }

    private fun toABGR(paint: Paint): Paint {
        val p = Paint(paint)
        if (isDrawPath) p.setXfermode(PorterDuffXfermode(PorterDuff.Mode.SRC))
        return p
    }

    private fun changeLight(paint: Paint, factor: Float) {
        val rawColor = paint.color
        val color = ((rawColor and -0x1000000)
                + (((rawColor and 0x00ff0000 shr 16) * factor).toInt() shl 16)
                + (((rawColor and 0x0000ff00 shr 8) * factor).toInt() shl 8)
                + ((rawColor and 0x000000ff) * factor).toInt())
        paint.setColor(color)
    }

    private val mHandler: Handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.what) {
                MSG_DP_CANCEL -> {
                    DpApi.dpClearAll()
                    DpApi.dpCannel()
                }
            }
        }
    }
    var drawBitmapEnable = true

    init {
        init()
    }

    override fun onDraw(canvas: Canvas) {
        Log.i(TAG, "onDraw: 花花花")
        super.onDraw(canvas)
        canvas.drawBitmap(bgBitmap!!, 0f, 0f, null)
        if (!drawBitmapEnable) {
            return
        }
        canvas.drawBitmap(mBitmap!!, 0f, 0f, null)
        if (!isAccelerate) {
            if (isEraseMode) {
                for (i in mCurrLines.indices) {
                    val line = mCurrLines[i]
                    canvas.drawCircle(
                        line!!.preX,
                        line.preY,
                        line.paint.strokeWidth / 2,
                        mEraserPaint!!
                    )
                }
            } else if (isDrawShape) {
                for (i in mCurrLines.indices) {
                    val line = mCurrLines[i]
                    canvas.drawRect((line as Shape?)!!.rectF, line!!.paint)
                }
            } else if (isDrawPath) {
                for (i in mCurrLines.indices) {
                    val line = mCurrLines[i]
                    canvas.drawPath(line!!.path, line.paint)
                }
            }
        }
    }

    companion object {
        const val TAG = "AccelerateView"
        const val CHANGE_VIEW_ALPHA = "com.ist.change_view_alpha"
        const val MODE_DRAW_PATH = 0
        const val MODE_ERASE = 1
        const val MODE_TOUCH_ERASE = 2
        const val MODE_DRAW_SHAPE = 3
        private const val MSG_DP_CANCEL = 0
    }
}
